package com.xinzhi.fiter;

import com.xinzhi.service.impl.SpringUserDetailsService;
import com.xinzhi.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    SpringUserDetailsService myUserDetailsService;
    @Autowired
    JwtTokenUtil jwtTokenUtil;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //从HTTP请求的头部中获取JWT令牌。jwtTokenUtil.getHeader() 返回JWT令牌的名称，通常存储在请求头中。
        String jwtToken  = request.getHeader(jwtTokenUtil.getHeader());
        if (!StringUtils.isEmpty(jwtToken)){
            //使用 jwtTokenUtil 解析JWT令牌，尝试从中提取用户名信息。
            String username = jwtTokenUtil.getUsernameFromToken(jwtToken);
            // 检查是否成功从JWT中提取用户名信息，并且当前上下文中没有已经经过身份验证的用户。
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null){
                //调用 myUserDetailsService 的 loadUserByUsername 方法，根据用户名加载用户的详细信息。
                UserDetails userDetails = myUserDetailsService.loadUserByUsername(username);
                //验证JWT令牌的有效性，确保其未过期且与用户信息匹配。
                if (jwtTokenUtil.validateToken(jwtToken,userDetails)){
                    //创建一个 UsernamePasswordAuthenticationToken 对象，将用户详细信息、凭证（此处为 null，因为JWT通常不包含密码）、用户的权限传递给该对象。
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    //将新创建的 authenticationToken 对象设置为安全上下文中的当前认证，表示用户已经被成功授权。
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        //继续执行过滤链中的下一个过滤器或请求处理程序
        filterChain.doFilter(request,response);
    }
}
